1 /**
  2  * 测试用例库文件,提供如event mock、iframe封装等各种常用功能 部分方法来源于YUI测试框架
  3  * @namespace UserAction
  4  * @name UserAction
  5  */
  6 UserAction = {
  7         beforedispatch:null,
  8         /**
  9          * 判断是否为function
 10          * @grammar isf
 11          * @param {Any}   value  判断的对象
 12          * @returns {Boolean} 真或假
 13          */
 14         isf /* is function ? */:function ( value ) {
 15                 return value && (typeof value == 'function');
 16         },
 17         /**
 18          * 判断是否为布尔类型
 19          * @grammar isb
 20          * @param {Any}   value  判断的对象
 21          * @returns {Boolean} 真或假
 22          */
 23         isb /* is boolean? */:function ( value ) {
 24                 return value && (typeof value == 'boolean');
 25         },
 26         /**
 27          * 判断是否为对象
 28          * @grammar iso
 29          * @param  {Any}  value  判断的对象
 30          * @returns {Boolean} 真或假
 31          */
 32         iso /* is object? */:function ( value ) {
 33                 return value && (typeof value == 'object');
 34         },
 35         /**
 36          * 判断是否为字符串
 37          * @grammar isos
 38          * @param  {Any}  value  判断的对象
 39          * @returns {Boolean} 真或假
 40          */
 41         iss /* is string? */:function ( value ) {
 42                 return value && (typeof value == 'string');
 43         },
 44         /**
 45          * 判断是否为数字
 46          * @grammar isn
 47          * @param  {Any} value  判断的对象
 48          * @returns {Boolean} 真或假
 49          */
 50         isn /* is number? */:function ( value ) {
 51                 return value && (typeof value == 'number');
 52         },
 53         // --------------------------------------------------------------------------
 54         // Generic event methods
 55         // --------------------------------------------------------------------------
 56 
 57         /**
 58          * 根据给定的事件信息模拟键盘事件,并冒泡到产生这个事件的对象上
 59          * @param {HTMLElement}   被触发事件的元素.
 60          * @param {String}   type 事件类型,如: keyup, keydown, 或 keypress.
 61          * @param {Boolean}  bubbles (Optional) 事件是否允许冒泡,默认为true
 62          * @param {Boolean}  cancelable (Optional) 事件是否允许通过preventDefault取消,默认是true.
 63          * @param {Window}  view (Optional) 触发事件的window容器,默认就是window
 64          * @param {Boolean}  ctrlKey (Optional) 触发事件时是否触发ctrl键的事件,默认为false.
 65          * @param {Boolean} altKey (Optional) I触发事件时是否触发atl键的事件,默认为false
 66          * @param {Boolean}  shiftKey (Optional) 触发事件时是否触发shift键的事件,默认为false.
 67          * @param {Boolean}  metaKey (Optional) 触发事件时是否触发meta键的事件,默认为false.
 68          * @param {int}   keyCode (Optional)  触发键盘事件时按下的键值(keycode),默认为0.
 69          * @param {int} charCode (Optional) 触发键盘事件时按下的Unicode值(charCode),默认为0.
 70          */
 71         simulateKeyEvent:function ( target /* :HTMLElement */, type /* :String */, bubbles /* :Boolean */, cancelable /* :Boolean */, view /* :Window */, ctrlKey /* :Boolean */, altKey /* :Boolean */, shiftKey /* :Boolean */, metaKey /* :Boolean */, keyCode /* :int */, charCode /* :int */ ) /* :Void */ {
 72                 // check target
 73                 target = typeof target == 'string' ? document.getElementById( target )
 74                     : target;
 75                 if ( !target ) {
 76                         throw new Error( "simulateKeyEvent(): Invalid target." );
 77                 }
 78 
 79                 // check event type
 80                 if ( typeof type == 'string' ) {
 81                         type = type.toLowerCase();
 82                         switch ( type ) {
 83                                 case "keyup":
 84                                 case "keydown":
 85                                 case "keypress":
 86                                         break;
 87                                 case "textevent": // DOM Level 3
 88                                         type = "keypress";
 89                                         break;
 90                                 // @TODO was the fallthrough intentional, if so throw error
 91                                 default:
 92                                         throw new Error( "simulateKeyEvent(): Event type '" + type
 93                                             + "' not supported." );
 94                         }
 95                 } else {
 96                         throw new Error( "simulateKeyEvent(): Event type must be a string." );
 97                 }
 98 
 99                 // setup default values
100                 if ( !this.isb( bubbles ) ) {
101                         bubbles = true; // all key events bubble
102                 }
103                 if ( !this.isb( cancelable ) ) {
104                         cancelable = true; // all key events can be cancelled
105                 }
106                 if ( !this.iso( view ) ) {
107                         view = window; // view is typically window
108                 }
109                 if ( !this.isb( ctrlKey ) ) {
110                         ctrlKey = false;
111                 }
112                 if ( !this.isb( typeof altKey == 'boolean' ) ) {
113                         altKey = false;
114                 }
115                 if ( !this.isb( shiftKey ) ) {
116                         shiftKey = false;
117                 }
118                 if ( !this.isb( metaKey ) ) {
119                         metaKey = false;
120                 }
121                 if ( !(typeof keyCode == 'number') ) {
122                         keyCode = 0;
123                 }
124                 if ( !(typeof charCode == 'number') ) {
125                         charCode = 0;
126                 }
127 
128                 // try to create a mouse event
129                 var customEvent /* :MouseEvent */ = null;
130 
131                 // check for DOM-compliant browsers first
132                 if ( this.isf( document.createEvent ) ) {
133 
134                         try {
135 
136                                 // try to create key event
137                                 customEvent = document.createEvent( "KeyEvents" );
138 
139                                 /*
140                                  * Interesting problem: Firefox implemented a non-standard
141                                  * version of initKeyEvent() based on DOM Level 2 specs. Key
142                                  * event was removed from DOM Level 2 and re-introduced in DOM
143                                  * Level 3 with a different interface. Firefox is the only
144                                  * browser with any implementation of Key Events, so for now,
145                                  * assume it's Firefox if the above line doesn't error.
146                                  */
147                                 // TODO: Decipher between Firefox's implementation and a correct
148                                 // one.
149                                 customEvent.initKeyEvent( type, bubbles, cancelable, view,
150                                     ctrlKey, altKey, shiftKey, metaKey, keyCode, charCode );
151 
152                         } catch ( ex /* :Error */ ) {
153 
154                                 /*
155                                  * If it got here, that means key events aren't officially
156                                  * supported. Safari/WebKit is a real problem now. WebKit 522
157                                  * won't let you set keyCode, charCode, or other properties if
158                                  * you use a UIEvent, so we first must try to create a generic
159                                  * event. The fun part is that this will throw an error on
160                                  * Safari 2.x. The end result is that we need another
161                                  * try...catch statement just to deal with this mess.
162                                  */
163                                 try {
164 
165                                         // try to create generic event - will fail in Safari 2.x
166                                         customEvent = document.createEvent( "Events" );
167 
168                                 } catch ( uierror /* :Error */ ) {
169 
170                                         // the above failed, so create a UIEvent for Safari 2.x
171                                         customEvent = document.createEvent( "UIEvents" );
172 
173                                 } finally {
174 
175                                         customEvent.initEvent( type, bubbles, cancelable );
176 
177                                         // initialize
178                                         customEvent.view = view;
179                                         customEvent.altKey = altKey;
180                                         customEvent.ctrlKey = ctrlKey;
181                                         customEvent.shiftKey = shiftKey;
182                                         customEvent.metaKey = metaKey;
183                                         customEvent.keyCode = keyCode;
184                                         customEvent.charCode = charCode;
185 
186                                 }
187 
188                         }
189 
190                         // before dispatch
191                         if ( this.beforedispatch && typeof this.beforedispatch == 'function' )
192                                 this.beforedispatch( customEvent );
193                         this.beforedispatch = null;
194 
195                         // fire the event
196                         target.dispatchEvent( customEvent );
197 
198                 } else if ( this.iso( document.createEventObject ) ) { // IE
199 
200                         // create an IE event object
201                         customEvent = document.createEventObject();
202 
203                         // assign available properties
204                         customEvent.bubbles = bubbles;
205                         customEvent.cancelable = cancelable;
206                         customEvent.view = view;
207                         customEvent.ctrlKey = ctrlKey;
208                         customEvent.altKey = altKey;
209                         customEvent.shiftKey = shiftKey;
210                         customEvent.metaKey = metaKey;
211 
212                         /*
213                          * IE doesn't support charCode explicitly. CharCode should take
214                          * precedence over any keyCode value for accurate representation.
215                          */
216                         customEvent.keyCode = (charCode > 0) ? charCode : keyCode;
217 
218                         // before dispatch
219                         if ( this.beforedispatch && typeof this.beforedispatch == 'function' )
220                                 this.beforedispatch( customEvent );
221                         this.beforedispatch = null;
222 
223                         // fire the event
224                         target.fireEvent( "on" + type, customEvent );
225 
226                 } else {
227                         throw new Error(
228                             "simulateKeyEvent(): No event simulation framework present." );
229                 }
230 
231                 this.beforedispatch = null;
232         },
233 
234         /**
235          * 模拟鼠标事件
236          * @param {HTMLElement} target 被触发事件的元素.
237          * @param {String} type 事件类型,如 click, dblclick, mousedown, mouseup, mouseout, mouseover, 和 mousemove
238          * @param {Boolean}  bubbles (Optional) 事件是否允许冒泡,默认为true
239          * @param {Boolean}  cancelable (Optional) 事件是否允许通过preventDefault取消,默认是true.
240          * @param {Window}  view (Optional) 触发事件的window容器,默认就是window
241          * @param {int}     detail (Optional) 鼠标按钮使用的次数,默认是1
242          * @param {int}  screenX (Optional) 事件触发时相对屏幕上的x坐标,默认是0
243          * @param {int} screenY (Optional) 事件触发时相对屏幕上的Y坐标,默认是0
244          * @param {int}     clientX (Optional)  事件触发时相对client上的X坐标,默认是0
245          * @param {int}   clientY (Optional) 事件触发时相对client上的Y坐标,默认是0
246          * @param {Boolean}  ctrlKey (Optional) 触发事件时是否触发ctrl键的事件,默认为false.
247          * @param {Boolean} altKey (Optional) I触发事件时是否触发atl键的事件,默认为false
248          * @param {Boolean}  shiftKey (Optional) 触发事件时是否触发shift键的事件,默认为false.
249          * @param {Boolean}  metaKey (Optional) 触发事件时是否触发meta键的事件,默认为false.
250          * @param {int}  button (Optional)  鼠标按下的键,0指左键,1中间键,2指右键,默认是0.
251          * @param {HTMLElement}  relatedTarget (Optional) 事件相关的目标元素,mouseout事件中指鼠标移动到的元素,mouseover指鼠标从哪一个元素移动过来,其他事件忽略这个参数,默认是null
252          */
253         simulateMouseEvent:function ( target /* :HTMLElement */, type /* :String */, bubbles /* :Boolean */, cancelable /* :Boolean */, view /* :Window */, detail /* :int */, screenX /* :int */, screenY /* :int */, clientX /* :int */, clientY /* :int */, ctrlKey /* :Boolean */, altKey /* :Boolean */, shiftKey /* :Boolean */, metaKey /* :Boolean */, button /* :int */, relatedTarget /* :HTMLElement */ ) /* :Void */ {
254 
255                 // check target
256                 target = typeof target == 'string' ? document.getElementById( target )
257                     : target;
258                 if ( !target ) {
259                         throw new Error( "simulateMouseEvent(): Invalid target." );
260                 }
261 
262                 // check event type
263                 if ( this.iss( type ) ) {
264                         type = type.toLowerCase();
265                         switch ( type ) {
266                                 case "mouseover":
267                                 case "mouseout":
268                                 case "mousedown":
269                                 case "mouseup":
270                                 case "click":
271                                 case "dblclick":
272                                 case "mousemove":
273                                 case "mouseenter":// 非标准支持,仅为测试提供,该项仅IE下work
274                                 case "mouseleave":
275                                         break;
276                                 default:
277                                         throw new Error( "simulateMouseEvent(): Event type '" + type
278                                             + "' not supported." );
279                         }
280                 } else {
281                         throw new Error(
282                             "simulateMouseEvent(): Event type must be a string." );
283                 }
284 
285                 // setup default values
286                 if ( !this.isb( bubbles ) ) {
287                         bubbles = true; // all mouse events bubble
288                 }
289                 if ( !this.isb( cancelable ) ) {
290                         cancelable = (type != "mousemove"); // mousemove is the only one
291                         // that can't be cancelled
292                 }
293                 if ( !this.iso( view ) ) {
294                         view = window; // view is typically window
295                 }
296                 if ( !this.isn( detail ) ) {
297                         detail = 1; // number of mouse clicks must be at least one
298                 }
299                 if ( !this.isn( screenX ) ) {
300                         screenX = 0;
301                 }
302                 if ( !this.isn( screenY ) ) {
303                         screenY = 0;
304                 }
305                 if ( !this.isn( clientX ) ) {
306                         clientX = 0;
307                 }
308                 if ( !this.isn( clientY ) ) {
309                         clientY = 0;
310                 }
311                 if ( !this.isb( ctrlKey ) ) {
312                         ctrlKey = false;
313                 }
314                 if ( !this.isb( altKey ) ) {
315                         altKey = false;
316                 }
317                 if ( !this.isb( shiftKey ) ) {
318                         shiftKey = false;
319                 }
320                 if ( !this.isb( metaKey ) ) {
321                         metaKey = false;
322                 }
323                 if ( !this.isn( button ) ) {
324                         button = 0;
325                 }
326 
327                 // try to create a mouse event
328                 var customEvent /* :MouseEvent */ = null;
329 
330                 // check for DOM-compliant browsers first
331                 if ( this.isf( document.createEvent ) ) {
332 
333                         customEvent = document.createEvent( "MouseEvents" );
334 
335                         // Safari 2.x (WebKit 418) still doesn't implement initMouseEvent()
336                         if ( this.browser.ie !== 9 && customEvent.initMouseEvent ) {
337                                 customEvent.initMouseEvent( type, bubbles, cancelable, view,
338                                     detail, screenX, screenY, clientX, clientY, ctrlKey,
339                                     altKey, shiftKey, metaKey, button, relatedTarget );
340                         } else { // Safari
341 
342                                 // the closest thing available in Safari 2.x is UIEvents
343                                 customEvent = document.createEvent( "UIEvents" );
344                                 customEvent.initEvent( type, bubbles, cancelable );
345                                 customEvent.view = view;
346                                 customEvent.detail = detail;
347                                 customEvent.screenX = screenX;
348                                 customEvent.screenY = screenY;
349                                 customEvent.clientX = clientX;
350                                 customEvent.clientY = clientY;
351                                 customEvent.ctrlKey = ctrlKey;
352                                 customEvent.altKey = altKey;
353                                 customEvent.metaKey = metaKey;
354                                 customEvent.shiftKey = shiftKey;
355                                 customEvent.button = button;
356                                 customEvent.relatedTarget = relatedTarget;
357                         }
358 
359                         /*
360                          * Check to see if relatedTarget has been assigned. Firefox versions
361                          * less than 2.0 don't allow it to be assigned via initMouseEvent()
362                          * and the property is readonly after event creation, so in order to
363                          * keep YAHOO.util.getRelatedTarget() working, assign to the IE
364                          * proprietary toElement property for mouseout event and fromElement
365                          * property for mouseover event.
366                          */
367                         if ( relatedTarget && !customEvent.relatedTarget ) {
368                                 if ( type == "mouseout" ) {
369                                         customEvent.toElement = relatedTarget;
370                                 } else if ( type == "mouseover" ) {
371                                         customEvent.fromElement = relatedTarget;
372                                 }
373                         }
374 
375                         // before dispatch
376                         if ( this.beforedispatch && typeof this.beforedispatch == 'function' )
377                                 this.beforedispatch( customEvent );
378                         this.beforedispatch = null;
379 
380                         // fire the event
381                         target.dispatchEvent( customEvent );
382 
383                 } else if ( this.iso( document.createEventObject ) ) { // IE
384 
385                         // create an IE event object
386                         customEvent = document.createEventObject();
387 
388                         // assign available properties
389                         customEvent.bubbles = bubbles;
390                         customEvent.cancelable = cancelable;
391                         customEvent.view = view;
392                         customEvent.detail = detail;
393                         customEvent.screenX = screenX;
394                         customEvent.screenY = screenY;
395                         customEvent.clientX = clientX;
396                         customEvent.clientY = clientY;
397                         customEvent.ctrlKey = ctrlKey;
398                         customEvent.altKey = altKey;
399                         customEvent.metaKey = metaKey;
400                         customEvent.shiftKey = shiftKey;
401 
402                         // fix button property for IE's wacky implementation
403                         switch ( button ) {
404                                 case 0:
405                                         customEvent.button = 1;
406                                         break;
407                                 case 1:
408                                         customEvent.button = 4;
409                                         break;
410                                 case 2:
411                                         // leave as is
412                                         break;
413                                 default:
414                                         customEvent.button = 0;
415                         }
416 
417                         /*
418                          * Have to use relatedTarget because IE won't allow assignment to
419                          * toElement or fromElement on generic events. This keeps
420                          * YAHOO.util.customEvent.getRelatedTarget() functional.
421                          */
422                         customEvent.relatedTarget = relatedTarget;
423 
424                         // before dispatch
425                         if ( this.beforedispatch && typeof this.beforedispatch == 'function' )
426                                 this.beforedispatch( customEvent );
427                         this.beforedispatch = null;
428                         // fire the event
429                         target.fireEvent( "on" + type, customEvent );
430 
431                 } else {
432                         throw new Error(
433                             "simulateMouseEvent(): No event simulation framework present." );
434                 }
435         },
436 
437         // --------------------------------------------------------------------------
438         // Mouse events
439         // --------------------------------------------------------------------------
440 
441         /**
442          * 在某一个元素上模拟鼠标事件
443          * @param {HTMLElement}  target 被触发鼠标事件的元素
444          * @param {String}  type 事件类型,如: click, dblclick, mousedown, mouseup, mouseout,mouseover, 和 mousemove.
445          * @param {Object} options 额外参数,使用DOM标准名称
446          * @method mouseEvent
447          * @static
448          */
449         fireMouseEvent:function ( target /* :HTMLElement */, type /* :String */, options /* :Object */ ) /* :Void */ {
450                 options = options || {};
451                 this.simulateMouseEvent( target, type, options.bubbles,
452                     options.cancelable, options.view, options.detail,
453                     options.screenX, options.screenY, options.clientX,
454                     options.clientY, options.ctrlKey, options.altKey,
455                     options.shiftKey, options.metaKey, options.button,
456                     options.relatedTarget );
457         },
458 
459         /**
460          * 模拟鼠标单击事件
461          * @remark 鼠标单击事件
462          * @param {HTMLElement} 单击的元素对象
463          * @param {Object} 单击事件的可选参数
464          * @method click
465          */
466         click:function ( target /* :HTMLElement */, options /* :Object */ ) /* :Void */ {
467                 this.fireMouseEvent( target, "click", options );
468         },
469 
470         /**
471          * 模拟鼠标双击事件
472          * @param {HTMLElement}双击的元素对象
473          * @param {Object}双击事件的可选参数
474          * @method dblclick
475          */
476         dblclick:function ( target /* :HTMLElement */, options /* :Object */ ) /* :Void */ {
477                 this.fireMouseEvent( target, "dblclick", options );
478         },
479 
480         /**
481          * 模拟鼠标左键按下
482          * @param {HTMLElement}  target  鼠标单击的对象
483          * @param {Object} options 额外参数,使用DOM标准名称
484          * @method mousedown
485          */
486         mousedown:function ( target /* :HTMLElement */, options /* Object */ ) /* :Void */ {
487                 this.fireMouseEvent( target, "mousedown", options );
488         },
489 
490         /**
491          * 模拟鼠标移动
492          * @param {HTMLElement}  target  鼠标事件的对象
493          * @param {Object} options 额外参数,使用DOM标准名称
494          * @method mousemove
495          */
496         mousemove:function ( target /* :HTMLElement */, options /* Object */ ) /* :Void */ {
497                 this.fireMouseEvent( target, "mousemove", options );
498         },
499 
500         /**模拟鼠标移出某一个元素事件
501          * @param {HTMLElement}  target  鼠标事件的对象
502          * @param {Object} options 额外参数,使用DOM标准名称
503          * @method mouseout
504          */
505         mouseout:function ( target /* :HTMLElement */, options /* Object */ ) /* :Void */ {
506                 this.fireMouseEvent( target, "mouseout", options );
507         },
508 
509         /**模拟鼠标移动经过某一个元素事件
510          * @param {HTMLElement}  target  鼠标事件的对象
511          * @param {Object} options 额外参数,使用DOM标准名称
512          * @method mouseover
513          * @static
514          */
515         mouseover:function ( target /* :HTMLElement */, options /* Object */ ) /* :Void */ {
516                 this.fireMouseEvent( target, "mouseover", options );
517         },
518 
519         /**
520          * 模拟鼠标左键在某一个元素上弹起
521          *
522          * @param {HTMLElement}  target  鼠标事件的对象
523          * @param {Object} options 额外参数,使用DOM标准名称
524          * @method mouseup
525          * @static
526          */
527         mouseup:function ( target /* :HTMLElement */, options /* Object */ ) /* :Void */ {
528                 this.fireMouseEvent( target, "mouseup", options );
529         },
530 
531         dragto:function ( target, options ) {
532                 var me = this;
533                 me.mousemove( target, {
534                         clientX:options.startX,
535                         clientY:options.startY
536                 } );
537                 setTimeout( function () {
538                         me.mousedown( target, {
539                                 clientX:options.startX,
540                                 clientY:options.startY
541                         } );
542                         setTimeout( function () {
543                                 me.mousemove( target, {
544                                         clientX:options.endX,
545                                         clientY:options.endY
546                                 } );
547                                 setTimeout( function () {
548                                         me.mouseup( target, {
549                                                 clientX:options.endX,
550                                                 clientY:options.endY
551                                         } );
552                                         if ( options.callback )
553                                                 options.callback();
554                                 }, options.aftermove || 20 );
555                         }, options.beforemove || 20 );
556                 }, options.beforestart || 50 );
557         },
558 
559         // --------------------------------------------------------------------------
560         // Key events
561         // --------------------------------------------------------------------------
562 
563         /**
564          * 触发键盘事件,需要设置keyCode或charCode
565          * @param {String}  type 键盘事件类型 ("keyup", "keydown" or "keypress").
566          * @param {HTMLElement}   目标元素
567          * @param {Object}   options  触发事件的参数,设置keyCode或charCode
568          * @method fireKeyEvent
569          * @static
570          */
571         fireKeyEvent:function ( type /* :String */, target /* :HTMLElement */, options /* :Object */ ) /* :Void */ {
572                 options = options || {};
573                 this.simulateKeyEvent( target, type, options.bubbles,
574                     options.cancelable, options.view, options.ctrlKey,
575                     options.altKey, options.shiftKey, options.metaKey,
576                     options.keyCode, options.charCode );
577         },
578 
579         /**
580          * 模拟键盘按下事件
581          * @param {HTMLElement}  target  鼠标事件的对象
582          * @param {Object} options 额外参数,使用DOM标准名称
583          * @method keydown
584          * @static
585          */
586         keydown:function ( target /* :HTMLElement */, options /* :Object */ ) /* :Void */ {
587                 this.fireKeyEvent( "keydown", target, options );
588         },
589 
590         /**
591          * 模拟键盘按键事件,包括鼠标按下和弹起
592          * @param {HTMLElement}  target  鼠标事件的对象
593          * @param {Object} options 额外参数,使用DOM标准名称
594          * @method keypress
595          */
596         keypress:function ( target /* :HTMLElement */, options /* :Object */ ) /* :Void */ {
597                 this.fireKeyEvent( "keypress", target, options );
598         },
599 
600         /**
601          * 模拟键盘弹起事件
602          * @param {HTMLElement}  target  鼠标事件的对象
603          * @param {Object} options 额外参数,使用DOM标准名称
604          */
605         keyup:function ( target /* :HTMLElement */, options /* Object */ ) /* :Void */ {
606                 this.fireKeyEvent( "keyup", target, options );
607         },
608 
609         /**
610          * 提供iframe扩展支持,用例测试需要独立场景的用例,由于异步支持,通过finish方法触发start
611          * <li>事件绑定在frame上,包括afterfinish和jsloaded
612          *
613          * @param op.win window对象
614          * @param op.nojs   不加载额外js
615          * @param op.ontest   测试步骤
616          * @param op.onbeforestart  {Function} 测试启动前处理步骤,默认为QUnit.stop();
617          * @param op.onafterfinish   {Function} 测试完毕执行步骤,默认为QUnit.start()
618          *
619          */
620         frameExt:function ( op ) {
621                 stop();
622                 op = typeof op == 'function' ? {
623                         ontest:op
624                 } : op;
625                 var pw = op.win || window, w, f, url = '', id = typeof op.id == 'undefined' ? 'f'
626                     : op.id, fid = 'iframe#' + id;
627 
628                 op.finish = function () {
629                         pw.$( fid ).unbind();
630                         setTimeout( function () {
631                                 pw.$( 'div#div' + id ).remove();
632                                 start();
633                         }, 20 );
634                 };
635 
636                 if ( pw.$( fid ).length == 0 ) {
637                         /* 添加frame,部分情况下,iframe没有边框,为了可以看到效果,添加一个带边框的div */
638                         pw.$( pw.document.body ).append( '<div id="div' + id + '"></div>' );
639                         pw.$( 'div#div' + id ).append( '<iframe id="' + id + '"></iframe>' );
640                 }
641                 op.onafterstart && op.onafterstart( $( 'iframe#f' )[0] );
642                 pw.$( 'script' ).each( function () {
643                         if ( this.src && this.src.indexOf( 'import.php' ) >= 0 ) {
644                                 url = this.src.split( 'import.php' )[1];
645                         }
646                 } );
647                 pw.$( fid ).one( 'load',
648                     function ( e ) {
649                             var w = e.target.contentWindow;
650                             var h = setInterval( function () {
651                                     if ( w.baidu ) {// 等待加载完成,IE6下这地方总出问题
652                                             clearInterval( h );
653                                             op.ontest( w, w.frameElement );
654                                     }
655                             }, 20 );
656                             // 找到当前操作的iframe,然后call ontest
657                     } ).attr( 'src', cpath + 'frame.php' + url );
658         },
659 
660         /**
661          *
662          * 判断2个数组是否相等
663          *
664          * @param {Array} array1
665          * @param {Array} array1
666          * @returns {Boolean} 真或假
667          */
668         isEqualArray:function ( array1, array2 ) {
669                 if ( '[object Array]' != Object.prototype.toString.call( array1 )
670                     || '[object Array]' != Object.prototype.toString.call( array2 ) )
671                         return (array1 === array2);
672                 else if ( array1.length != array2.length )
673                         return false;
674                 else {
675                         for ( var i in array1 ) {
676                                 if ( array1[i] != array2[i] )
677                                         return false;
678                         }
679                         return true;
680                 }
681         },
682 
683         /*
684          *
685          * 通用数据模块
686          *
687          * @static
688          *
689          */
690         commonData:{// 针对测试文件的路径而不是UserAction的路径
691                 "testdir":'../../',
692                 datadir:(function () {
693                         return location.href.split( "/test/" )[0] + "/test/tools/data/";
694                 })(),
695                 currentPath:function () {
696                         var params = location.search.substring( 1 ).split( '&' );
697                         for ( var i = 0; i < params.length; i++ ) {
698                                 var p = params[i];
699                                 if ( p.split( '=' )[0] == 'case' ) {
700                                         var casepath = p.split( '=' )[1].split( '.' ).join( '/' );
701                                         return location.href.split( '/test/' )[0] + '/test/'
702                                             + casepath.substring( 0, casepath.lastIndexOf( '/' ) )
703                                             + '/';
704                                 }
705                         }
706                         return "";
707                 }
708         },
709 
710         importsrc:function ( src, callback, matcher, exclude, win ) {
711                 win = win || window;
712                 var doc = win.document;
713 
714                 var srcpath = location.href.split( "/_test/" )[0]
715                     + "/_test/tools/br/import.php";
716                 var param0 = src;
717                 var ps = {
718                         f:src
719                 };
720                 if ( exclude )
721                         ps.e = exclude;
722                 var param1 = exclude || "";
723                 /**
724                  * IE下重复载入会出现无法执行情况
725                  */
726                 if ( win.execScript ) {
727                         $.get( srcpath, ps, function ( data ) {
728                                 win.execScript( data );
729                         } );
730                 } else {
731                         var head = doc.getElementsByTagName( 'head' )[0];
732                         var sc = doc.createElement( 'script' );
733                         sc.type = 'text/javascript';
734                         sc.src = srcpath + "?f=" + param0 + "&e=" + param1;
735                         head.appendChild( sc );
736                 }
737 
738                 matcher = matcher || src;
739                 var mm = matcher.split( "," )[0].split( "." );
740                 var h = setInterval( function () {
741                         var p = win;
742                         for ( var i = 0; i < mm.length; i++ ) {
743                                 if ( typeof (p[mm[i]]) == 'undefined' ) {
744                                         // console.log(mm[i]);
745                                         return;
746                                 }
747                                 p = p[mm[i]];
748                         }
749                         clearInterval( h );
750                         if ( callback && 'function' == typeof callback )
751                                 callback();
752                 }, 20 );
753         },
754 
755         /* *
756          用于加载css文件,如果没有加载完毕则不执行回调函数
757          */
758         loadcss:function ( url, callback, classname, style, value ) {
759                 var links = document.getElementsByTagName( 'link' );
760                 for ( var link in links ) {
761                         if ( link.href == url ) {
762                                 callback();
763                                 return;
764                         }
765                 }
766                 var head = document.getElementsByTagName( 'head' )[0];
767                 var link = head.appendChild( document.createElement( 'link' ) );
768                 link.setAttribute( "rel", "stylesheet" );
769                 link.setAttribute( "type", "text/css" );
770                 link.setAttribute( "href", url );
771                 var div = document.body.appendChild( document.createElement( "div" ) );
772                 $( document ).ready(
773                     function () {
774                             div.className = classname || 'cssloaded';
775                             var h = setInterval( function () {
776                                     if ( $( div ).css( style || 'width' ) == value
777                                         || $( div ).css( style || 'width' ) == '20px' ) {
778                                             clearInterval( h );
779                                             document.body.removeChild( div );
780                                             setTimeout( callback, 20 );
781                                     }
782                             }, 20 );
783                     } );
784         },
785 
786         /**
787          * 在一段时间内不断查询oncheck是否返回true,如果是则执行onsuccess,否则超时结束后执行onfail
788          * @param {Function} oncheck 回调函数,定期检查某一个结果是否正确,如果是则返回true
789          * @param {Function} onsuccess,oncheck返回true时执行
790          * @param {Function} onfail 超时结束时执行,用例失败
791          * @param timeout {Number} 超时时间
792          */
793         delayhelper:function ( oncheck, onsuccess, onfail, timeout ) {
794                 onsuccess = onsuccess || oncheck.onsuccess;
795                 onfail = onfail || oncheck.onfail || function () {
796                         window.QUnit.fail( 'timeout wait for timeout : ' + timeout + 'ms' );
797                         start();
798                 };
799                 timeout = timeout || oncheck.timeout || 10000;
800 
801                 oncheck = (typeof oncheck == 'function') ? oncheck : oncheck.oncheck;
802                 var h1 = setInterval( function () {
803                         if ( !oncheck() )
804                                 return;
805                         else {
806                                 clearInterval( h1 );
807                                 clearTimeout( h2 );
808                                 typeof onsuccess == "function" && onsuccess();
809                         }
810                 }, 20 );
811                 var h2 = setTimeout( function () {
812                         clearInterval( h1 );
813                         clearTimeout( h2 );
814                         onfail();
815                 }, timeout );
816         },
817         /**
818          * @name browser
819          * @see UserAction.brower.ie,UserAction.brower.chrome,UserAction.brower.webkit
820          */
821         browser:(function () {
822                 var win = window;
823 
824                 var numberify = function ( s ) {
825                         var c = 0;
826                         return parseFloat( s.replace( /\./g, function () {
827                                 return (c++ == 1) ? '' : '.';
828                         } ) );
829                 },
830 
831                     nav = win && win.navigator,
832 
833                     o = {
834 
835                             /**
836                              * 判断是否为ie并返回ie的版本
837                              *@namespace UserAction
838                              * @name UserAction.browser.ie
839                              * @property ie ie的版本号
840                              * @type float
841                              * @return {Number} ie版本号
842                              * @static
843                              */
844                             ie:0,
845 
846                             /**
847                              *
848                              * 判断是否为opera并返回opera的版本
849                              *@namespace UserAction
850                              * @name UserAction.browser.opera
851                              * @property opera opera版本号
852                              * @type float
853                              * @return {Number} opera版本号
854                              * @static
855                              */
856                             opera:0,
857 
858                             /**
859                              *  是否是Gecko引擎
860                              * <pre>
861                              * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
862                              * Firefox 1.5.0.9: 1.8.0.9 <-- 1.8
863                              * Firefox 2.0.0.3: 1.8.1.3 <-- 1.81
864                              * Firefox 3.0   <-- 1.9
865                              * Firefox 3.5   <-- 1.91
866                              * </pre>
867                              *
868                              * 判断是否为gecko
869                              *@namespace UserAction
870                              * @name UserAction.browser.gecko
871                              * @property gecko gecko版本号
872                              * @type float
873                              * @return {Number} 0或非0
874                              * @static
875                              */
876                             gecko:0,
877 
878                             /**
879                              *
880                              * 判断是否为webkit并返回webkit的版本
881                              *@namespace UserAction
882                              * @name UserAction.browser.webkit
883                              * @property webkit webkit的版本号
884                              * @type float
885                              * @return {Number} 0或非0
886                              * @static
887                              */
888                             webkit:0,
889 
890                             /**
891                              * 判断是否为chrome并返回chrome的版本
892                              *@namespace UserAction
893                              * @name UserAction.browser.chrome
894                              * @property chrome chrome版本号
895                              * @type float
896                              * @return  {Number} 0或非0(chrome版本号)
897                              * @static
898                              */
899                             chrome:0,
900                             /**
901                              * 判断是否为safari并返回safari的版本
902                              *@namespace UserAction
903                              * @name UserAction.browser.safari
904                              * @property safari safari版本号
905                              * @type float
906                              * @return  {Number} 0或非0(safari版本号)
907                              * @static
908                              */
909                             safari:0,
910                             /**
911                              * 判断是否为firefox并返回firefox的版本
912                              *@namespace UserAction
913                              * @name UserAction.browser.firefox
914                              * @property firefox firefoxi版本号
915                              * @type float
916                              * @return  {Number} 0或非0(firefox版本号)
917                              * @static
918                              */
919                             firefox:0,
920                             /**
921                              * 判断是否为maxthon并返回maxthon的版本
922                              *@namespace UserAction
923                              * @name UserAction.browser.firefox
924                              * @property maxthon maxthon版本号
925                              * @type float
926                              * @return  {Number} 0或非0(maxthon版本号)
927                              * @static
928                              */
929                             maxthon:0,
930                             /**
931                              * 判断是否为maxthon的IE模式
932                              *@namespace UserAction
933                              * @name UserAction.browser.maxthonIE
934                              * @property maxthonIE  是否是遨游的IE模式
935                              * @type float
936                              * @return  {Number} 0或1
937                              * @static
938                              */
939                             maxthonIE:0,
940 
941                             /**
942                              * Currently limited to Safari on the iPhone/iPod Touch,
943                              * Nokia N-series devices with the WebKit-based browser, and Opera
944                              * Mini.
945                              * 判断是否为移动设备上的浏览器
946                              *@namespace UserAction
947                              * @name UserAction.browser.mobile
948                              * @property mobile
949                              * @type string
950                              * @static
951                              */
952                             mobile:null,
953 
954                             /**
955                              * Adobe AIR version number or 0. Only populated if webkit is
956                              * detected. Example: 1.0
957                              *
958                              * @property air
959                              * @type float
960                              */
961                             air:0,
962 
963                             /**
964                              * Google Caja version number or 0.
965                              *
966                              * @property caja
967                              * @type float
968                              */
969                             caja:nav && nav.cajaVersion,
970 
971                             /**
972                              * Set to true if the pagebreak appears to be in SSL
973                              *
974                              * @property secure
975                              * @type boolean
976                              * @static
977                              */
978                             secure:false,
979 
980                             /**
981                              * The operating system. Currently only detecting windows or
982                              * macintosh
983                              *
984                              * @property os
985                              * @type string
986                              * @static
987                              */
988                             os:null
989 
990                     },
991 
992                     ua = nav && nav.userAgent,
993 
994                     loc = win && win.location,
995 
996                     href = loc && loc.href,
997 
998                     m;
999 
1000                 o.secure = href && (href.toLowerCase().indexOf( "https" ) === 0);
1001 
1002                 if ( ua ) {
1003 
1004                         if ( (/windows|win32/i).test( ua ) ) {
1005                                 o.os = 'windows';
1006                         } else if ( (/macintosh/i).test( ua ) ) {
1007                                 o.os = 'macintosh';
1008                         } else if ( (/rhino/i).test( ua ) ) {
1009                                 o.os = 'rhino';
1010                         }
1011 
1012                         // Modern KHTML browsers should qualify as Safari X-Grade
1013                         if ( (/KHTML/).test( ua ) ) {
1014                                 o.webkit = 1;
1015                         }
1016                         if ( window.external && /(\d+\.\d)/.test( external.max_version ) ) {
1017 
1018                                 o.maxthon = parseFloat( RegExp['\x241'] );
1019                                 if ( /MSIE/.test( ua ) ) {
1020                                         o.maxthonIE = 1;
1021                                         o.maxthon = 0;
1022                                 }
1023 
1024                         }
1025                         // Modern WebKit browsers are at least X-Grade
1026                         m = ua.match( /AppleWebKit\/([^\s]*)/ );
1027                         if ( m && m[1] ) {
1028                                 o.webkit = numberify( m[1] );
1029 
1030                                 // Mobile browser check
1031                                 if ( / Mobile\//.test( ua ) ) {
1032                                         o.mobile = "Apple"; // iPhone or iPod Touch
1033                                 } else {
1034                                         m = ua.match( /NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/ );
1035                                         if ( m ) {
1036                                                 o.mobile = m[0]; // Nokia N-series, Android, webOS,
1037                                                 // ex:
1038                                                 // NokiaN95
1039                                         }
1040                                 }
1041 
1042                                 var m1 = ua.match( /Safari\/([^\s]*)/ );
1043                                 if ( m1 && m1[1] ) // Safari
1044                                         o.safari = numberify( m1[1] );
1045                                 m = ua.match( /Chrome\/([^\s]*)/ );
1046                                 if ( o.safari && m && m[1] ) {
1047                                         o.chrome = numberify( m[1] ); // Chrome
1048                                 } else {
1049                                         m = ua.match( /AdobeAIR\/([^\s]*)/ );
1050                                         if ( m ) {
1051                                                 o.air = m[0]; // Adobe AIR 1.0 or better
1052                                         }
1053                                 }
1054                         }
1055 
1056                         if ( !o.webkit ) { // not webkit
1057                                 // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316;
1058                                 // fi; U;
1059                                 // try get firefox and it's ver
1060                                 // ssr)
1061                                 m = ua.match( /Opera[\s\/]([^\s]*)/ );
1062                                 if ( m && m[1] ) {
1063                                         o.opera = numberify( m[1] );
1064                                         m = ua.match( /Opera Mini[^;]*/ );
1065                                         if ( m ) {
1066                                                 o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
1067                                         }
1068                                 } else { // not opera or webkit
1069                                         m = ua.match( /MSIE\s([^;]*)/ );
1070                                         if ( m && m[1] ) {
1071                                                 o.ie = numberify( m[1] );
1072                                         } else { // not opera, webkit, or ie
1073                                                 m = ua.match( /Gecko\/([^\s]*)/ );
1074                                                 if ( m ) {
1075                                                         o.gecko = 1; // Gecko detected, look for revision
1076                                                         m = ua.match( /rv:([^\s\)]*)/ );
1077                                                         if ( m && m[1] ) {
1078                                                                 o.gecko = numberify( m[1] );
1079                                                         }
1080                                                 }
1081                                         }
1082                                 }
1083                         }
1084                 }
1085 
1086                 return o;
1087         })(),
1088 
1089         /**
1090          * 提供队列方式执行用例的方案,接口包括start、add、next,方法全部执行完毕时会启动用例继续执行
1091          */
1092         functionListHelper:function () {
1093                 var check = {
1094                         list:[],
1095                         start:function () {
1096                                 var self = this;
1097                                 $( this ).bind( 'next', function () {
1098                                         setTimeout( function () {// 避免太深的堆栈
1099                                                 if ( self.list.length == 0 )
1100                                                         start();
1101                                                 else
1102                                                         self.list.shift()();
1103                                         }, 0 );
1104                                 } );
1105                                 self.next();
1106                         },
1107                         add:function ( func ) {
1108                                 this.list.push( func );
1109                         },
1110                         next:function ( delay ) {
1111                                 var self = this;
1112                                 if ( delay ) {
1113                                         setTimeout( function () {
1114                                                 $( self ).trigger( 'next' );
1115                                         }, delay );
1116                                 } else
1117                                         $( this ).trigger( 'next' );
1118                         }
1119                 };
1120                 return check;
1121         },
1122         /**
1123          * 获取某一个元素的outerHTML
1124          */
1125         getHTML:function ( co ) {
1126                 var div = document.createElement( 'div' ), h;
1127                 if ( !co )
1128                         return 'null';
1129                 div.appendChild( co.cloneNode( true ) );
1130                 h = div.innerHTML.toLowerCase();
1131 
1132                 h = h.replace( /[\r\n\t\u200b\ufeff]/g, '' ); // Remove line feeds and tabs
1133                 h = h.replace( / (\w+)=([^\"][^\s>]*)/gi, ' $1="$2"' ); // Restore
1134                 // attribs on IE
1135                 return h;
1136         },
1137         /**
1138          * 获取某一个元素的innerHTML,去掉了不可见字符
1139          */
1140         getChildHTML:function ( co ) {
1141 
1142                 var h = co.innerHTML.toLowerCase();
1143 
1144                 h = h.replace( /[\r\n\t\u200b\ufeff]/g, '' ); // Remove line feeds and tabs
1145                 h = h.replace( / (\w+)=([^\"][^\s>]*)/gi, ' $1="$2"' ); // Restore attribs on IE
1146 
1147                 return h.replace( /\u200B/g, '' );
1148         },
1149         /**
1150          *获取某一个节点在父节点所有孩子中的顺序
1151          * @param node 需要获取顺序的节点
1152          * @returns {Number} 顺序号,从0开始计数
1153          */
1154         getIndex:function ( node ) {
1155                 var childNodes = node.parentNode.childNodes, i = 0;
1156                 while ( childNodes[i] !== node )
1157                         i++;
1158                 return i;
1159         },
1160         /**
1161          *清除不可见字符
1162          * @param node 需要清除不可见文本子节点的节点
1163          */
1164         manualDeleteFillData:function ( node ) {
1165                 var childs = node.childNodes;
1166                 for ( var i = 0; i < childs.length; i++ ) {
1167                         var fillData = childs[i];
1168                         if ( (fillData.nodeType == 3) && ( fillData.data == domUtils.fillChar ) ) {
1169                                 domUtils.remove( fillData );
1170                                 fillData = null;
1171 
1172                         }
1173                         else
1174                                 this.manualDeleteFillData( fillData );
1175                 }
1176 
1177 
1178         },
1179         /**
1180          * 统一cssFloat和styleFloat
1181          */
1182         cssStyleToDomStyle:function ( cssName ) {
1183                 var test = document.createElement( 'div' ).style,
1184                     cssFloat = test.cssFloat != undefined ? 'cssFloat'
1185                         : test.styleFloat != undefined ? 'styleFloat'
1186                         : 'float',
1187                     cache = { 'float':cssFloat };
1188 
1189                 function replacer( match ) {
1190                         return match.charAt( 1 ).toUpperCase();
1191                 }
1192 
1193 //        return function( cssName ) {
1194                 return cache[cssName] || (cache[cssName] = cssName.replace( /-./g, replacer ) );
1195 //        };
1196         },
1197         /**
1198          判断两个元素的所有样式是否相同
1199          *@param elementA 比较的一个元素
1200          * @param elementB 比较的另一个元素
1201          * @returns {Boolean} true或false
1202          */
1203         isSameStyle:function ( elementA, elementB ) {
1204                 var styleA = elementA.style.cssText,
1205                     styleB = elementB.style.cssText;
1206                 if ( this.browser.ie && this.browser.version == 6 ) {
1207                         styleA = styleA.toLowerCase();
1208                         styleB = styleB.toLowerCase();
1209                 }
1210                 if ( !styleA && !styleB ) {
1211                         return true;
1212                 } else if ( !styleA || !styleB ) {
1213                         return false;
1214                 }
1215                 var styleNameMap = {},
1216                     record = [],
1217                     exit = {};
1218                 styleA.replace( /[\w-]+\s*(?=:)/g, function ( name ) {
1219                         styleNameMap[name] = record.push( name );
1220                 } );
1221                 try {
1222                         styleB.replace( /[\w-]+\s*(?=:)/g, function ( name ) {
1223                                 var index = styleNameMap[name];
1224                                 if ( index ) {
1225 //                    name = this.cssStyleToDomStyle( name );
1226                                         if ( elementA.style[name] !== elementB.style[name] ) {
1227                                                 throw exit;
1228                                         }
1229                                         record[index - 1] = '';
1230                                 } else {
1231                                         throw exit;
1232                                 }
1233                         } );
1234                 } catch ( ex ) {
1235                         if ( ex === exit ) {
1236                                 return false;
1237                         }
1238                 }
1239                 return !record.join( '' );
1240         },
1241         /**
1242          *  判断两个元素的所有属性是否都相同
1243          *  @param nodeA 比较的第一个节点
1244          *  @param nodeB 比较的另一个节点
1245          *  @returns {Boolean} true或false
1246          */
1247         hasSameAttrs:function ( nodeA, nodeB ) {
1248                 if ( nodeA.tagName != nodeB.tagName )
1249                         return 0;
1250                 var thisAttribs = nodeA.attributes,
1251                     otherAttribs = nodeB.attributes;
1252                 if ( thisAttribs.length != otherAttribs.length )
1253                         return 0;
1254                 if ( thisAttribs.length == 0 )
1255                         return 1;
1256                 var attrA, attrB;
1257                 for ( var i = 0; attrA = thisAttribs[i++]; ) {
1258                         if ( attrA.nodeName == 'style' ) {
1259                                 if ( this.isSameStyle( nodeA, nodeB ) ) {
1260                                         continue
1261                                 } else {
1262                                         return 0;
1263                                 }
1264                         }
1265                         if ( !ua.browser.ie || attrA.specified ) {
1266                                 attrB = nodeB.attributes[attrA.nodeName];
1267                                 if ( !attrB ) {
1268                                         return 0;
1269                                 }
1270                         }
1271                         return 1;
1272                 }
1273                 return 1;
1274         },
1275 
1276         flag:true,
1277         /**
1278          *检查两个节点(包含所有子节点)是否具有相同的属性
1279          *  @param nodeA 比较的第一个节点
1280          *  @param nodeB 比较的另一个节点
1281          *  @returns {Boolean} true或false
1282          */
1283         checkAllChildAttribs:function ( nodeA, nodeB ) {
1284                 var k = nodeA.childNodes.length;
1285                 if ( k != nodeB.childNodes.length )
1286                         this.flag = false;
1287                 if ( !this.flag )
1288                         return this.flag;
1289                 while ( k ) {
1290                         var tmpNodeA = nodeA.childNodes[k - 1];
1291                         var tmpNodeB = nodeB.childNodes[k - 1];
1292                         k--;
1293 
1294                         if ( tmpNodeA.nodeType == 3 || tmpNodeB.nodeType == 3 || tmpNodeA.nodeType == 8 || tmpNodeB.nodeType == 8 )
1295                                 continue;
1296                         if ( !this.hasSameAttrs( tmpNodeA, tmpNodeB ) ) {
1297                                 this.flag = false;
1298                                 break;
1299 
1300                         }
1301 
1302                         this.checkAllChildAttribs( tmpNodeA, tmpNodeB );
1303                 }
1304                 return this.flag;
1305         },
1306         /**
1307          * 判断两个节点(包括所有子孙节点)所有的属性及style是否都相同
1308          *  @param nodeA 比较的第一个节点
1309          *  @param nodeB 比较的另一个节点
1310          *  @returns {Boolean} true或false
1311          */
1312         haveSameAllChildAttribs:function ( nodeA, nodeB ) {
1313                 this.flag = true;
1314                 return this.checkAllChildAttribs( nodeA, nodeB );
1315         },
1316         /**
1317          * 查看传入的html是否与传入的元素ele具有相同的style,比较结束会执行QUnit的断言
1318          * @param {String} html 被比较的html字符串
1319          * @param {HTMLElement} doc 当前的document对象
1320          * @param {HTMLElement} ele 要被比较的元素,html与ele的innerHTML比较
1321          * @descript {String} descript 断言的描述性语句
1322          */
1323         checkHTMLSameStyle:function ( html, doc, ele, descript ) {
1324                 var tagEle = doc.createElement( ele.tagName );
1325                 tagEle.innerHTML = html;
1326                 /*会有一些不可见字符,在比较前提前删掉*/
1327                 this.manualDeleteFillData( ele );
1328                 ok( this.haveSameAllChildAttribs( ele, tagEle ), descript );
1329 //        ok(this.equalsNode(ele.innerHMTL,html),descript);
1330         },
1331 
1332         /**
1333          * 得到选中区域的文本
1334          * @returns {String} 选中区域的文本
1335          */
1336         getSelectedText:function () {
1337                 if ( window.getSelection ) {
1338                         // This technique is the most likely to be standardized.
1339                         // getSelection() returns a Selection object, which we do not document.
1340                         return window.getSelection().toString();
1341                 }
1342                 else if ( document.getSelection ) {
1343                         // This is an older, simpler technique that returns a string
1344                         return document.getSelection();
1345                 }
1346                 else if ( document.selection ) {
1347                         // This is the IE-specific technique.
1348                         // We do not document the IE selection property or TextRange objects.
1349                         return document.selection.createRange().text;
1350                 }
1351         },
1352         /**
1353          * 找到给定元素的左上角和右下角顶点的横坐标和纵坐标
1354          * @param {HTMLElement} oElement
1355          * @return {Array} [startX,startY,endX,endY]
1356          */
1357         findPosition:function ( oElement ) {
1358                 var x2 = 0;
1359                 var y2 = 0;
1360                 var width = oElement.offsetWidth;
1361                 var height = oElement.offsetHeight;
1362                 if ( typeof( oElement.offsetParent ) != 'undefined' ) {
1363                         for ( var posX = 0, posY = 0; oElement; oElement = oElement.offsetParent ) {
1364                                 posX += oElement.offsetLeft;
1365                                 posY += oElement.offsetTop;
1366                         }
1367                         x2 = posX + width;
1368                         y2 = posY + height;
1369                         return [ posX, posY , x2, y2];
1370 
1371                 } else {
1372                         x2 = oElement.x + width;
1373                         y2 = oElement.y + height;
1374                         return [ oElement.x, oElement.y, x2, y2];
1375                 }
1376         },
1377         /**
1378          获取元素的float属性,ie下用styleFloat获取,非ie用cssFloat
1379          @param {HTMLElement} ele 要获取float属性的元素
1380          @returns {String} ele的float属性
1381          */
1382         getFloatStyle:function ( ele ) {
1383                 if ( this.browser.ie )
1384                         return ele.style['styleFloat'];
1385                 else
1386                         return ele.style['cssFloat'];
1387         }
1388 
1389 
1390 };
1391 var ua = UserAction;
1392 var upath = ua.commonData.currentPath();
1393 var cpath = ua.commonData.datadir;